home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / brushOp.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  13KB  |  466 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/StringDefs.h>
  17. #include <X11/Shell.h>
  18. #include <X11/Xaw/Box.h>
  19. #include <X11/Xaw/Form.h>
  20. #include <X11/Xaw/Command.h>
  21. #include <X11/Xaw/Toggle.h>
  22. #include "xpaint.h"
  23. #include "misc.h"
  24. #include "Paint.h"
  25.  
  26. #include "bitmaps/paintA.xbm"
  27. #include "bitmaps/paintB.xbm"
  28. #include "bitmaps/paintC.xbm"
  29. #include "bitmaps/paintD.xbm"
  30. #include "bitmaps/paintE.xbm"
  31. #include "bitmaps/paintF.xbm"
  32. #include "bitmaps/paintG.xbm"
  33. #include "bitmaps/paintH.xbm"
  34. #include "bitmaps/paintI.xbm"
  35. #include "bitmaps/paintJ.xbm"
  36. #include "bitmaps/paintK.xbm"
  37. #include "bitmaps/paintL.xbm"
  38. #include "bitmaps/paintM.xbm"
  39. #include "bitmaps/paintN.xbm"
  40. #include "bitmaps/paintO.xbm"
  41. #include "bitmaps/paintP.xbm"
  42. #include "bitmaps/paintQ.xbm"
  43. #include "bitmaps/paintR.xbm"
  44. #include "bitmaps/paintS.xbm"
  45. #include "bitmaps/paintT.xbm"
  46.  
  47. #define BRUSH(name)     \
  48.     (char *)CONCAT(name,_bits), CONCAT(name,_width), CONCAT(name,_height)
  49.  
  50. typedef struct {
  51.     Pixmap    pixmap;
  52.     Cursor    cursor;
  53.     char    *bits;
  54.     int    width, height;
  55. } BrushItem;
  56.  
  57. static BrushItem    brushList[] = {
  58.     { None, None, BRUSH(paintA) },
  59.     { None, None, BRUSH(paintB) },
  60.     { None, None, BRUSH(paintC) },
  61.     { None, None, BRUSH(paintD) },
  62.     { None, None, BRUSH(paintE) },
  63.     { None, None, BRUSH(paintF) },
  64.     { None, None, BRUSH(paintG) },
  65.     { None, None, BRUSH(paintH) },
  66.     { None, None, BRUSH(paintI) },
  67.     { None, None, BRUSH(paintJ) },
  68.     { None, None, BRUSH(paintK) },
  69.     { None, None, BRUSH(paintL) },
  70.     { None, None, BRUSH(paintM) },
  71.     { None, None, BRUSH(paintN) },
  72.     { None, None, BRUSH(paintO) },
  73.     { None, None, BRUSH(paintP) },
  74.     { None, None, BRUSH(paintQ) },
  75.     { None, None, BRUSH(paintR) },
  76.     { None, None, BRUSH(paintS) },
  77.     { None, None, BRUSH(paintT) },
  78. };
  79.  
  80. #define default_bits    paintA_bits
  81. #define default_width    paintA_width
  82. #define default_height    paintA_height
  83.  
  84. typedef struct {
  85.     Boolean    isErase, useSecond;
  86.     Pixmap    pixmap;
  87.     int    width, height;
  88. } LocalInfo;
  89.  
  90. static BrushItem    *currentBrush = NULL;
  91. static Boolean        eraseMode = True;
  92.  
  93. static void     draw(Widget w, OpInfo *info, LocalInfo *l, int x, int y)
  94. {
  95.     XRectangle    undo;
  96.     int        sx = x - l->width / 2;
  97.     int        sy = y - l->height / 2;
  98.     GC        gc;
  99.  
  100.     if (l->isErase)
  101.         gc = info->base_gc;
  102.     else 
  103.         gc = l->useSecond ? info->second_gc : info->first_gc;
  104.  
  105.     XSetClipOrigin(XtDisplay(w), gc, sx, sy);
  106.  
  107.     if (l->isErase && eraseMode && info->base != None) {
  108.         XCopyArea(XtDisplay(w), info->base, info->drawable,
  109.                 gc, sx, sy, l->width, l->height, sx, sy);
  110.     } else {
  111.         XFillRectangle(XtDisplay(w), info->drawable, 
  112.                 gc, sx, sy, l->width, l->height);
  113.     }
  114.  
  115.     if (info->surface == opPixmap) {
  116.         XYtoRECT(sx, sy, sx + l->width, sy + l->height, &undo);
  117.  
  118.         UndoGrow(w, sx, sy);
  119.         UndoGrow(w, sx + l->width, sy + l->height);
  120.         PwUpdate(w, &undo, False);
  121.     }
  122. }
  123.  
  124. static void    press(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info) 
  125. {
  126.     /*
  127.     **  Check to make sure all buttons are up, before doing this
  128.     */
  129.     if ((event->state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)) != 0)
  130.         return;
  131.  
  132.     if (info->surface == opWindow && info->isFat)
  133.         return;
  134.  
  135.     l->useSecond = event->button == Button2;
  136.     l->width     = currentBrush->width;
  137.     l->height    = currentBrush->height;
  138.  
  139.     XSetClipMask(XtDisplay(w), info->first_gc, l->pixmap);
  140.     XSetClipMask(XtDisplay(w), info->second_gc, l->pixmap);
  141.     XSetClipMask(XtDisplay(w), info->base_gc, l->pixmap);
  142.     
  143.     UndoStart(w, info);
  144.  
  145.     draw(w, info, l, event->x, event->y);
  146. }
  147.  
  148. static void    motion(Widget w, LocalInfo *l, XMotionEvent *event, OpInfo *info) 
  149. {
  150.     if (info->surface == opWindow && info->isFat)
  151.         return;
  152.  
  153.     draw(w, info, l, event->x, event->y);
  154. }
  155.  
  156. static void    release(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info) 
  157. {
  158.     int    mask;
  159.     /*
  160.     **  Check to make sure all buttons are up, before doing this
  161.     */
  162.     mask = Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask;
  163.     switch (event->button) {
  164.     case Button1:    mask ^= Button1Mask; break;
  165.     case Button2:    mask ^= Button2Mask; break;
  166.     case Button3:    mask ^= Button3Mask; break;
  167.     case Button4:    mask ^= Button4Mask; break;
  168.     case Button5:    mask ^= Button5Mask; break;
  169.     }
  170.     if ((event->state & mask) != 0)
  171.         return;
  172.  
  173.     XSetClipMask(XtDisplay(w), info->first_gc, None);
  174.     XSetClipMask(XtDisplay(w), info->second_gc, None);
  175.     XSetClipMask(XtDisplay(w), info->base_gc, None);
  176. }
  177.  
  178. static void    setPixmap(Widget w, void *brushArg)
  179. {
  180.     BrushItem    *brush = (BrushItem *)brushArg;
  181.     LocalInfo    *l = (LocalInfo*)GraphicGetData(w);
  182.  
  183.     l->pixmap = brush->pixmap;
  184. }
  185.  
  186. static void    setCursor(Widget w, void *brushArg)
  187. {
  188.     static Boolean    inited = False;
  189.     static XColor    xcols[2];
  190.     BrushItem    *brush = (BrushItem *)brushArg;
  191.     Display        *dpy = XtDisplay(w);
  192.  
  193.     if (!inited) {
  194.         Colormap    map;
  195.         Screen        *screen = XtScreen(w);
  196.  
  197.         inited = True;
  198.         xcols[0].pixel = WhitePixelOfScreen(screen);
  199.         xcols[1].pixel = BlackPixelOfScreen(screen);
  200.  
  201.         XtVaGetValues(w, XtNcolormap, &map, NULL);
  202.  
  203.         XQueryColors(dpy, map, xcols, XtNumber(xcols));
  204.     }
  205.     if (brush->cursor == None) {
  206.         Pixmap    mask;
  207.         XImage    *src, *msk;
  208.         GC    gc;
  209.         Boolean    flg;
  210.         int    x, y;
  211.  
  212.         src = XGetImage(dpy, brush->pixmap, 0, 0, brush->width,
  213.                     brush->height, AllPlanes, ZPixmap);
  214.         msk = NewXImage(dpy, NULL, 1, brush->width, brush->height);
  215.         for (y = 0; y < brush->height; y++) {
  216.             for (x = 0; x < brush->width; x++) {
  217.                 Pixel    p = XGetPixel(src, x, y);
  218.  
  219.                 flg = (Boolean)p;
  220.             
  221.                 if (!flg && x > 0)
  222.                     flg = XGetPixel(src, x - 1, y);
  223.                 if (!flg && x < brush->width - 1)
  224.                     flg = XGetPixel(src, x + 1, y);
  225.                 if (!flg && y > 0)
  226.                     flg = XGetPixel(src, x, y - 1);
  227.                 if (!flg && y < brush->height - 1)
  228.                     flg = XGetPixel(src, x, y + 1);
  229.                 
  230.                 XPutPixel(msk, x, y, flg);
  231.             }
  232.         }
  233.         mask = XCreatePixmap(dpy, brush->pixmap, brush->width, brush->height, 1);
  234.         gc = XCreateGC(dpy, mask, 0, 0);
  235.         XPutImage(dpy, mask, gc, msk, 0, 0, 0, 0, brush->width, brush->height);
  236.         XDestroyImage(src);
  237.         XDestroyImage(msk);
  238.         XFreeGC(dpy, gc);
  239.  
  240.         brush->cursor = XCreatePixmapCursor(dpy, brush->pixmap, mask, 
  241.                  &xcols[1], &xcols[0], 
  242.                 brush->width / 2, brush->height / 2);
  243.         XFreePixmap(dpy, mask);
  244.     }
  245.     XtVaSetValues(w, XtNcursor, brush->cursor, NULL);
  246. }
  247.  
  248. /*
  249. **  Those public functions
  250. */
  251. Boolean    EraseGetMode()
  252. {
  253.     return eraseMode;
  254. }
  255. void EraseSetMode(Boolean  mode)
  256. {
  257.     eraseMode = mode;
  258. }
  259. void *BrushAdd(Widget w)
  260. {
  261.     LocalInfo    *l = XtNew(LocalInfo);
  262.  
  263.     XtVaSetValues(w, XtNcompress, False, NULL);
  264.  
  265.     l->isErase = False;
  266.     l->pixmap  = currentBrush->pixmap;
  267.  
  268.     OpAddEventHandler(w, opWindow|opPixmap, ButtonPressMask, 
  269.             FALSE, (OpEventProc)press, (XtPointer)l);
  270.     OpAddEventHandler(w, opWindow|opPixmap, ButtonMotionMask, 
  271.             FALSE, (OpEventProc)motion, (XtPointer)l);
  272.     OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, 
  273.             FALSE, (OpEventProc)release, (XtPointer)l);
  274.  
  275.     setCursor(w, (void*)currentBrush);
  276.  
  277.     return l;
  278. }
  279. void BrushRemove(Widget w, LocalInfo *l)
  280. {
  281.     OpRemoveEventHandler(w, opWindow|opPixmap, ButtonPressMask, 
  282.             FALSE, (OpEventProc)press, (XtPointer)l);
  283.     OpRemoveEventHandler(w, opWindow|opPixmap, ButtonMotionMask, 
  284.             FALSE, (OpEventProc)motion, (XtPointer)l);
  285.     OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, 
  286.             FALSE, (OpEventProc)release, (XtPointer)l);
  287.  
  288.     XtFree((XtPointer)l);
  289. }
  290. void *EraseAdd(Widget w)
  291. {
  292.     LocalInfo    *l = XtNew(LocalInfo);
  293.  
  294.     XtVaSetValues(w, XtNcompress, False, NULL);
  295.  
  296.     l->isErase = True;
  297.     l->pixmap  = currentBrush->pixmap;
  298.  
  299.     OpAddEventHandler(w, opWindow|opPixmap, ButtonPressMask, 
  300.             FALSE, (OpEventProc)press, (XtPointer)l);
  301.     OpAddEventHandler(w, opWindow|opPixmap, ButtonMotionMask, 
  302.             FALSE, (OpEventProc)motion, (XtPointer)l);
  303.     OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, 
  304.             FALSE, (OpEventProc)release, (XtPointer)l);
  305.  
  306.     setCursor(w, (void*)currentBrush);
  307.  
  308.     return l;
  309. }
  310. void EraseRemove(Widget w, LocalInfo *l)
  311. {
  312.     OpRemoveEventHandler(w, opWindow|opPixmap, ButtonPressMask, 
  313.             FALSE, (OpEventProc)press, (XtPointer)l);
  314.     OpRemoveEventHandler(w, opWindow|opPixmap, ButtonMotionMask, 
  315.             FALSE, (OpEventProc)motion, (XtPointer)l);
  316.     OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask, 
  317.             FALSE, (OpEventProc)release, (XtPointer)l);
  318.         
  319.     XtFree((XtPointer)l);
  320. }
  321.  
  322. /*
  323. **  Initializer to create a default brush
  324. */
  325.  
  326. void    BrushInit(Widget toplevel)
  327. {
  328.     currentBrush = &brushList[0];
  329.     currentBrush->pixmap = XCreatePixmapFromBitmapData(
  330.         XtDisplay(toplevel), 
  331.         RootWindowOfScreen(XtScreen(toplevel)),
  332.         currentBrush->bits,
  333.         currentBrush->width,
  334.         currentBrush->height,
  335.         False, True, 1);
  336. }
  337.  
  338. /*
  339. **  The brush selection dialog
  340. */
  341.  
  342. static void    closePopup(Widget button, Widget shell)
  343. {
  344.     XtPopdown(shell);
  345. }
  346.  
  347. static void     selectBrush(Widget shell, BrushItem *nc)
  348. {
  349.     currentBrush = nc;
  350.  
  351.     if (((int)CurrentOp[0] == (int)BrushAdd) ||
  352.         ((int)CurrentOp[0] == (int)EraseAdd)) {
  353.         GraphicAll(setCursor, (void*)currentBrush);
  354.         GraphicAll(setPixmap, (void*)currentBrush);
  355.     }
  356. }
  357.  
  358. static Widget    createDialog(Widget w)
  359. {
  360.     Widget        shell, form, box, icon, firstIcon = 0, close;
  361.     GC        gc, igc;
  362.     XGCValues    values;
  363.     int        i;
  364.     Pixel        fg, bg;
  365.     Pixmap        pix;
  366.  
  367.     shell = XtVaCreatePopupShell("brush",
  368.             topLevelShellWidgetClass, w,
  369.             NULL);
  370.  
  371.     form = XtVaCreateManagedWidget(NULL,
  372.             formWidgetClass, shell,
  373.             NULL);
  374.  
  375.     box  = XtVaCreateManagedWidget("box",
  376.             boxWidgetClass, form,
  377.             NULL);
  378.  
  379.     values.foreground    = WhitePixelOfScreen(XtScreen(w));
  380.     values.background    = BlackPixelOfScreen(XtScreen(w));
  381.  
  382.     gc = XCreateGC(XtDisplay(w), 
  383.             RootWindowOfScreen(XtScreen(w)),
  384.             GCForeground|GCBackground, &values);
  385.  
  386.     values.background    = WhitePixelOfScreen(XtScreen(w));
  387.     values.foreground    = BlackPixelOfScreen(XtScreen(w));
  388.     igc = XCreateGC(XtDisplay(w), 
  389.             RootWindowOfScreen(XtScreen(w)),
  390.             GCForeground|GCBackground, &values);
  391.  
  392.     for (i = 0; i < XtNumber(brushList); i++) {
  393.         if (brushList[i].pixmap == None)
  394.             brushList[i].pixmap = XCreatePixmapFromBitmapData(
  395.                 XtDisplay(box), 
  396.                 RootWindowOfScreen(XtScreen(box)),
  397.                 brushList[i].bits,
  398.                 brushList[i].width,
  399.                 brushList[i].height,
  400.                 False, True, 1);
  401.  
  402.         icon = XtVaCreateManagedWidget("icon",
  403.                 toggleWidgetClass, box,
  404.                 XtNradioGroup, firstIcon,
  405.                 NULL);
  406.  
  407.         pix = XCreatePixmap(XtDisplay(box), 
  408.                     RootWindowOfScreen(XtScreen(box)),
  409.                     brushList[i].width,
  410.                     brushList[i].height,
  411.                     DefaultDepthOfScreen(XtScreen(box)));
  412.     
  413.         XtVaGetValues(icon, XtNforeground, &fg,
  414.                     XtNbackground, &bg,
  415.                     NULL);
  416.  
  417.         /*
  418.         **  Clear then draw the clipped rectangle in
  419.         */
  420.         XSetClipMask(XtDisplay(w), gc, None);
  421.         XSetForeground(XtDisplay(w), gc, bg);
  422.         XFillRectangle(XtDisplay(w), pix, gc, 0, 0,
  423.                 brushList[i].width, brushList[i].height);
  424.         XSetClipMask(XtDisplay(w), gc, brushList[i].pixmap);
  425.         XSetForeground(XtDisplay(w), gc, fg);
  426.         XFillRectangle(XtDisplay(w), pix, gc, 0, 0,
  427.                 brushList[i].width, brushList[i].height);
  428.  
  429.         XtVaSetValues(icon, XtNbitmap, pix, NULL);
  430.  
  431.         if (firstIcon == NULL) {
  432.             XtVaSetValues(icon, XtNstate, True, NULL);
  433.             firstIcon = icon;
  434.         }
  435.  
  436.         XtAddCallback(icon, XtNcallback, 
  437.                 (XtCallbackProc)selectBrush, (XtPointer)&brushList[i]);
  438.     }
  439.  
  440.     close  = XtVaCreateManagedWidget("close",
  441.             commandWidgetClass, form,
  442.             XtNfromVert, box,
  443.             XtNtop, XtChainBottom,
  444.             NULL);
  445.  
  446.     XtAddCallback(close, XtNcallback, (XtCallbackProc)closePopup, (XtPointer)shell);
  447.  
  448.     XFreeGC(XtDisplay(w), gc);
  449.     XFreeGC(XtDisplay(w), igc);
  450.  
  451.     AddDestroyCallback(shell, (void (*)(Widget, void *, XEvent *))closePopup, shell);
  452.  
  453.     return shell;
  454. }
  455.  
  456. void    BrushSelect(Widget w)
  457. {
  458.     static Widget    popup = NULL;
  459.  
  460.     if (popup == NULL) 
  461.         popup = createDialog(GetToplevel(w));
  462.     
  463.     XtPopup(popup, XtGrabNone);
  464.     XMapRaised(XtDisplay(popup), XtWindow(popup));
  465. }
  466.